package luke.audio.analyzer;

import java.io.File;
import java.util.*;

import luke.audio.analyzer.UniversalAudioDecoder.AudioData;

import luke.audio.processing.AudioChannelProcessor;

/**
 * BPM检测器类
 * 整合音频解码、频谱分析和BPM计算功能，提供完整的BPM检测解决方案
 */
public class BPMDetector {

    // BPM计算器实例
    private BPMCalculator bpmCalculator;
    // 频带定义
    public static final double[] FREQUENCY_BANDS = {
            0, 30, // 超低频 (Sub-Bass)
            30, 60, // 极低频
            60, 100, // 低频 (Kick Drum)
            100, 150, // 低频 (Bass)
            150, 250, // 低中频
            250, 400, // 低中频 (Low-Mid)
            400, 600, // 中频
            600, 1000, // 中频 (Mid)
            1000, 1600, // 中高频
            1600, 2500, // 中高频 (Upper-Mid)
            2500, 3500, // 高频
            3500, 5000, // 高频 (Presence)
            5000, 8000, // 高频 (Brilliance)
            8000, 12000, // 超高频 (Hi-Hat/Cymbals)
            12000, 20000 // 极高频 (Air)
    };
    private double audioDurationSec;
    private SpectrumAnalyzer spectrumAnalyzer;
    private AudioData audioData;
    private int audioDurationMs;
    private double[][] spectrogram;
    // 添加左右声道的频谱图
    private double[][] leftSpectrogram;
    private double[][] rightSpectrogram;
    // 下采样提高处理速度（使用原始多声道数据进行下采样）
    int targetRate = 44100; // 提高目标采样率以保持更多时间信息
    int fftSize = 2048;// 窗口大小
    int hopSize = 512;// 减小hopSize以提高时间分辨率
    double bpm;

    // 添加一个字段来存储频带能量信号
    private List<double[]> bandEnergySignals = new ArrayList<>();
    
    // 添加一个字段来存储最佳频带索引列表
    private List<Integer> coreBandIndices = new ArrayList<>();
    
    // 添加一个字段来存储重复BPM结果
    private RepeatedBPMResult repeatedBPMResult;
    
    // 添加一个字段来存储最佳频带索引
    private int coreBandIndex = -1;

    /**
     * 无参构造函数
     */
    public BPMDetector() {
        this.bpmCalculator = new BPMCalculator();
    }
    
    /**
     * 带文件参数的构造函数
     * 
     * @param audioFile 音频文件
     * @throws Exception 处理过程中可能出现的异常
     */
    public BPMDetector(File audioFile) throws Exception {
        this(); // 调用无参构造函数初始化bpmCalculator
        processAudioFile(audioFile);
    }
    
    /**
     * 处理音频文件
     * 
     * @param audioFile 音频文件
     * @throws Exception 处理过程中可能出现的异常
     */
    public void processAudioFile(File audioFile) throws Exception {
        // 使用UniversalAudioDecoder解码音频文件
        UniversalAudioDecoder decoder = new UniversalAudioDecoder();
        audioData = decoder.decodeAudioFile(audioFile);
        
        // 计算音频时长（毫秒）
        audioDurationSec = (double) audioData.data.length / (audioData.sampleRate * audioData.channels);
        audioDurationMs = (int) (audioDurationSec * 1000);
        
        // 对音频数据进行预处理
        preprocessAudioData();
        
        // 初始化频谱分析器
        spectrumAnalyzer = new SpectrumAnalyzer(targetRate, fftSize);
        
        // 处理声道数据
        if (audioData.channels == 1) {
            // 单声道处理
            float[] monoData = audioData.data;
            // 下采样
            float[] downsampledData = AudioChannelProcessor.downsample(monoData, audioData.sampleRate, targetRate);
            // 计算频谱图
            spectrogram = spectrumAnalyzer.computeSpectrogram(downsampledData, hopSize);
        } else if (audioData.channels == 2) {
            // 双声道处理
            AudioChannelProcessor.ChannelSpectrogram channelSpectrogram = 
                AudioChannelProcessor.processStereoChannels(audioData, targetRate, fftSize, hopSize);
            leftSpectrogram = channelSpectrogram.getLeftSpectrogram();
            rightSpectrogram = channelSpectrogram.getRightSpectrogram();
        } else {
            throw new IllegalArgumentException("不支持的声道数: " + audioData.channels);
        }
        
        // 检测BPM
        bpm = detectBPMFromSpectrum();
    }
    
    /**
     * 基于频谱数据检测BPM信息
     *
     * @return BPM结果对象
     */
    private double detectBPMFromSpectrum() {
        try {
            // 存储所有BPM结果（仅左右声道）
            List<Double> allSegmentBPMs = new ArrayList<>();

            // 处理左声道
            processSpectrogramForBPM(leftSpectrogram != null ? leftSpectrogram : spectrogram, allSegmentBPMs);

            // 如果存在右声道数据，也处理右声道
            if (rightSpectrogram != null) {
                processSpectrogramForBPM(rightSpectrogram, allSegmentBPMs);
            }

            // 确保至少有一个有效的BPM值
            if (allSegmentBPMs.isEmpty()) {
                return 0;
            }
            // 计算各频带最多重复BPM
            repeatedBPMResult = calculateMostRepeatedBPM(allSegmentBPMs);
            // 保持原始BPM值的精度，不进行四舍五入（四舍五入操作应该在BeatDetector中进行）
            double finalBPM = repeatedBPMResult.mostRepeatedBPM;


            // 返回结果
            return finalBPM;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 处理频谱图以提取BPM信息（新版本：循环所有频带能量，得到BPM和循环次数）
     *
     * @param spectrogram 要处理的频谱图
     * @param allBPMs     存储所有BPM结果的列表
     */
    private void processSpectrogramForBPM(double[][] spectrogram, List<Double> allBPMs) {
        try {
            // 频带能量分析
            double[][] bandEnergy = spectrumAnalyzer.computeBandEnergy(spectrogram, FREQUENCY_BANDS);

            // 准备多个频带的能量信号
            List<double[]> energySignals = new ArrayList<>();
            for (int band = 0; band < bandEnergy[0].length; band++) {
                double[] energySignal = new double[bandEnergy.length];
                for (int i = 0; i < bandEnergy.length; i++) {
                    energySignal[i] = bandEnergy[i][band];
                }
                energySignals.add(energySignal);
            }

            // 添加能量信号归一化处理
            energySignals = normalizeEnergySignals(energySignals);
            
            // 保存频带能量信号供BeatDetector使用
            this.bandEnergySignals = energySignals;
            
            // 循环所有频带能量，得到BPM和循环次数
            List<BandBPMInfo> bandBPMInfos = new ArrayList<>(); // 存储所有频带的BPM信息
            
            for (int bandIndex = 0; bandIndex < energySignals.size(); bandIndex++) {
                double[] energySignal = energySignals.get(bandIndex);
                
                // 使用新的calculateBPMWithCount方法获取BPM和循环次数
                BPMCalculator.BPMResult result = bpmCalculator.calculateBPMWithCount(energySignal, targetRate, hopSize);
                
                // 只有当BPM有效时才处理
                if (result.bpm > 0) {
                    bandBPMInfos.add(new BandBPMInfo(bandIndex, result.bpm, result.count));
                    
                }
            }
            
            // 如果没有有效的BPM结果，直接返回
            if (bandBPMInfos.isEmpty()) {
                return;
            }
            
            // 创建一个列表，将每个BPM按照其重复次数展开
            List<Double> expandedBPMs = new ArrayList<>();
            for (BandBPMInfo info : bandBPMInfos) {
                // 将每个BPM按照其重复次数添加到列表中
                for (int i = 0; i < info.count; i++) {
                    expandedBPMs.add(info.bpm);
                }
            }
            
            // 对展开的BPM列表进行归一化分组统计
            Map<Double, Integer> bpmCountMap = new HashMap<>();
            double tolerance = 0.01; // 1%的容差
            
            for (Double bpm : expandedBPMs) {
                boolean foundGroup = false;
                // 检查是否与已有的组中的值接近
                for (Double groupBase : bpmCountMap.keySet()) {
                    // 计算两个BPM值的比值差异
                    double ratio = Math.max(bpm, groupBase) / Math.min(bpm, groupBase);
                    // 如果比值接近1（差异在1%以内），则认为是同一组
                    if (Math.abs(ratio - 1.0) < tolerance) {
                        // 属于同一组，增加计数
                        bpmCountMap.put(groupBase, bpmCountMap.get(groupBase) + 1);
                        foundGroup = true;
                        break;
                    }
                }

                // 如果没有找到相近的组，则创建新组
                if (!foundGroup) {
                    bpmCountMap.put(bpm, 1);
                }
            }
            
            // 找到重复次数最多的BPM值（可能有多个）
            int maxCount = 0;
            List<Double> mostFrequentBPMs = new ArrayList<>();
            List<Integer> mostFrequentBandIndices = new ArrayList<>();

            // 首先找到最大次数
            for (Map.Entry<Double, Integer> entry : bpmCountMap.entrySet()) {
                if (entry.getValue() > maxCount) {
                    maxCount = entry.getValue();
                }
            }

            // 收集所有具有最大次数的BPM值
            for (Map.Entry<Double, Integer> entry : bpmCountMap.entrySet()) {
                if (entry.getValue() == maxCount) {
                    mostFrequentBPMs.add(entry.getKey());
                }
            }

            // 查找与最高频率BPM对应的频带索引
            for (Double bpm : mostFrequentBPMs) {
                int minBandIndex = Integer.MAX_VALUE; // 记录最小的频带索引
                for (BandBPMInfo info : bandBPMInfos) {
                    // 检查BPM是否接近mostFrequentBPM（在容差范围内）
                    double ratio = Math.max(info.bpm, bpm) / Math.min(info.bpm, bpm);
                    if (Math.abs(ratio - 1.0) < tolerance) {
                        // 选择频率最低（索引最小）的频带
                        if (info.bandIndex < minBandIndex) {
                            minBandIndex = info.bandIndex;
                        }
                    }
                }
                // 只添加索引最小的频带
                if (minBandIndex != Integer.MAX_VALUE) {
                    mostFrequentBandIndices.add(minBandIndex);
                }
            }

            // 输出调试信息

            // 输出所有选中的频带信息
            for (int i = 0; i < mostFrequentBPMs.size(); i++) {
                Double bpm = mostFrequentBPMs.get(i);
                int bandIndex = mostFrequentBandIndices.get(i);
            }

            // 保存核心频带索引列表和单个核心频带索引
            this.coreBandIndices = mostFrequentBandIndices;
            if (!mostFrequentBandIndices.isEmpty()) {
                this.coreBandIndex = mostFrequentBandIndices.get(0); // 保持向后兼容
            }

            // 将所有选中的BPM添加到allBPMs中
            for (Double bpm : mostFrequentBPMs) {
                allBPMs.add(bpm);
            }

            // 注意：在选出最佳频带和BPM后，不需要再对每个段进行BPM计算
            // 因为最佳频带已经确定，其BPM值也已经计算完成
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 对音频数据进行预处理：降噪、标准化、低音增强和人声去除
     */
    private void preprocessAudioData() {
        // 应用移动平均滤波进行降噪
        float[] filteredData = AudioPreprocessor.movingAverageFilter(audioData.data, 5);
        
        // 标准化音频信号到 [-1, 1] 范围
        float[] normalizedData = AudioPreprocessor.normalize(filteredData);
        
        // 增强低音并减弱高音
        float[] processedData = enhanceBassAndReduceTreble(normalizedData);
        
        // 去除人声（如果适用）
        float[] vocalRemovedData = AudioPreprocessor.removeVocal(processedData, audioData.channels);
        
        // 如果人声去除改变了声道数（从立体声变为单声道），需要更新AudioData
        int newChannels = audioData.channels;
        if (audioData.channels == 2 && vocalRemovedData.length != processedData.length) {
            // 人声去除将立体声转换为单声道
            newChannels = 1;
        }
        
        // 创建新的AudioData对象
        audioData = new AudioData(vocalRemovedData, audioData.sampleRate, newChannels);
    }
    
    /**
     * 增强低音并减弱高音
     * 
     * @param signal 输入信号
     * @return 处理后的信号
     */
    private float[] enhanceBassAndReduceTreble(float[] signal) {
        // 定义频带：只增强低音(0-250Hz)，减弱高音(8000-20000Hz)
        double[] frequencyBands = {
            0, 250,      // 低音频带 (增强)
            8000, 20000  // 高音频带 (减弱)
        };
        
        // 设置增益值：低音增益1.5(适度增强)，高音增益0.3(明显减弱)
        double[] bandGains = {
            1.5,  // 低音增益（适度增强）
            0.3   // 高音增益（明显减弱）
        };
        
        // 创建均衡器并应用
        AudioPreprocessor.Equalizer equalizer = new AudioPreprocessor.Equalizer(frequencyBands, bandGains);
        return equalizer.apply(signal, audioData.sampleRate);
    }
    
    /**
     * 从能量信号计算平均锐度和前20%锐度窗口的平均锐度
     * 
     * @param energySignal 能量信号
     * @return 包含平均锐度和前20%锐度窗口平均锐度的数组，索引0为平均锐度，索引1为前20%锐度窗口平均锐度
     */
    private double[] calculateBandSharpnessAndEnergyFromEnergySignal(double[] energySignal) {
        if (energySignal.length == 0) {
            return new double[]{0.0, 0.0};
        }
        
        // 计算每个时间窗口的锐度（与周围窗口的比值）
        List<Double> windowSharpness = new ArrayList<>();
        
        // 计算每个时间窗口的能量和锐度
        for (int i = 0; i < energySignal.length; i++) {
            // 计算核心窗口的平均能量
            // 当前默认使用单个窗口作为核心窗口，后续可根据频带特点调整核心窗口数
            int coreWindowSize = 1; // 核心窗口数，默认为1
            double coreEnergy = 0; // 核心窗口的能量总和
            int coreCount = 0; // 核心窗口的数量
            
            // 计算核心窗口的能量总和（当前实现为中心窗口）
            for (int k = Math.max(0, i - coreWindowSize/2); k <= Math.min(energySignal.length - 1, i + coreWindowSize/2); k++) {
                coreEnergy += energySignal[k];
                coreCount++;
            }
            
            // 计算核心窗口的平均能量
            double coreAverageEnergy = coreCount > 0 ? coreEnergy / coreCount : 0;
            
            // 计算窗口外的平均能量（前后各几个时间窗口）
            int surroundWindowSize = 5; // 简化处理，前后各5个时间窗口
            double surroundEnergy = 0; // 周围时间窗口的能量总和
            int surroundCount = 0; // 周围时间窗口的数量
            
            // 计算前面几个时间窗口的能量总和
            for (int j = Math.max(0, i - coreWindowSize/2 - surroundWindowSize); j < i - coreWindowSize/2; j++) {
                if (j >= 0) {
                    surroundEnergy += energySignal[j]; // 累加第j个时间窗口的能量
                    surroundCount++;
                }
            }
            
            // 计算后面几个时间窗口的能量总和
            for (int j = i + coreWindowSize/2 + 1; j <= Math.min(energySignal.length - 1, i + coreWindowSize/2 + surroundWindowSize); j++) {
                surroundEnergy += energySignal[j]; // 累加第j个时间窗口的能量
                surroundCount++;
            }
            
            if (surroundCount > 0) {
                // 计算周围时间窗口的平均能量
                double surroundAverageEnergy = surroundEnergy / surroundCount;
                // 计算锐度：核心窗口平均能量与周围时间窗口平均能量的比值
                double sharpness = surroundAverageEnergy > 0 ? coreAverageEnergy / surroundAverageEnergy : 0.0;
                windowSharpness.add(sharpness);
            } else {
                windowSharpness.add(0.0);
            }
        }
        
        // 如果没有足够的数据，返回默认值
        if (windowSharpness.isEmpty()) {
            return new double[]{0.0, 0.0};
        }
        
        // 计算平均锐度
        double totalSharpness = 0;
        for (double sharpness : windowSharpness) {
            totalSharpness += sharpness;
        }
        double averageSharpness = totalSharpness / windowSharpness.size();
        
        // 计算前20%锐度窗口的平均锐度
        // 创建锐度列表并按锐度降序排序
        List<Double> sortedSharpness = new ArrayList<>(windowSharpness);
        sortedSharpness.sort(Collections.reverseOrder());
        
        // 选取前20%的窗口
        int topCount = Math.max(1, (int) (sortedSharpness.size() * 0.2));
        
        // 计算前20%锐度窗口的平均锐度
        double totalTopSharpness = 0;
        for (int i = 0; i < topCount; i++) {
            totalTopSharpness += sortedSharpness.get(i);
        }
        double averageTopSharpness = totalTopSharpness / topCount;
        
        return new double[]{averageSharpness, averageTopSharpness};
    }

    /**
     * 计算各频带中出现最多的BPM值（考虑倍频关系）
     * 简化算法：
     * 1. 由于在BPMCalculator中已经将BPM归化到了120左右，这里直接进行统计
     * 2. 统计新集合的众数和出现第二频繁的数
     * 3. 当第一频繁和第二频繁相差比较大时(第一和第二的比值小于0.98时),则输出两个bpm
     *
     * @param allBPMs 所有BPM值列表（包括各频带BPM和合并BPM）
     * @return 最多重复BPM结果
     */
    private RepeatedBPMResult calculateMostRepeatedBPM(List<Double> allBPMs) {
        // 收集所有BPM值
        if (allBPMs.isEmpty()) {
            return new RepeatedBPMResult(0, 0, 0, 0); // 当没有BPM值时返回0而不是默认值
        }

        // 由于在BPMCalculator中已经将BPM归化到了120左右，这里直接进行统计
        // 使用基于比值的容差来分组相似的BPM值
        double ratioTolerance = 0.005; // 比值容差0.5%
        Map<Double, Integer> bpmCountMap = new HashMap<>();

        for (Double bpm : allBPMs) {
            boolean foundGroup = false;
            // 检查是否与已有的组中的值接近
            for (Double groupBase : bpmCountMap.keySet()) {
                // 计算两个BPM值的比值差异
                double ratio = Math.max(bpm, groupBase) / Math.min(bpm, groupBase);
                // 如果比值接近1（差异在0.5%以内），则认为是同一组
                if (Math.abs(ratio - 1.0) < ratioTolerance) {
                    // 属于同一组，增加计数
                    bpmCountMap.put(groupBase, bpmCountMap.get(groupBase) + 1);
                    foundGroup = true;
                    break;
                }
            }

            // 如果没有找到相近的组，则创建新组
            if (!foundGroup) {
                bpmCountMap.put(bpm, 1);
            }
        }

        // 找到重复次数最多和第二多的BPM值
        double mostFrequentBPM = 0;
        double secondMostFrequentBPM = 0;
        int maxCount = 0;
        int secondMaxCount = 0;

        // 将bpmCountMap转换为列表并排序
        List<Map.Entry<Double, Integer>> sortedEntries = new ArrayList<>(bpmCountMap.entrySet());
        sortedEntries.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));

        if (!sortedEntries.isEmpty()) {
            Map.Entry<Double, Integer> firstEntry = sortedEntries.get(0);
            mostFrequentBPM = firstEntry.getKey();
            maxCount = firstEntry.getValue();

            if (sortedEntries.size() > 1) {
                Map.Entry<Double, Integer> secondEntry = sortedEntries.get(1);
                secondMostFrequentBPM = secondEntry.getKey();
                secondMaxCount = secondEntry.getValue();
            }
        }

        // 创建结果对象并添加sourceBPMs
        RepeatedBPMResult result = new RepeatedBPMResult(mostFrequentBPM, maxCount, secondMostFrequentBPM, secondMaxCount);
        
        // 添加所有参与统计的BPM值到sourceBPMs中
        for (Double bpm : allBPMs) {
            result.sourceBPMs.add(bpm);
        }
        
        return result;
    }

    /**
     * 添加能量信号归一化方法
     * 对能量信号进行归一化处理，使不同频带的能量具有可比性
     *
     * @param energySignals 能量信号列表
     * @return 归一化后的能量信号列表
     */
    private List<double[]> normalizeEnergySignals(List<double[]> energySignals) {
        List<double[]> normalizedSignals = new ArrayList<>();

        for (double[] signal : energySignals) {
            // 计算信号的均方根值
            double rms = 0;
            for (double value : signal) {
                rms += value * value;
            }
            rms = Math.sqrt(rms / signal.length);

            // 避免除以零
            if (rms == 0) {
                normalizedSignals.add(signal.clone());
                continue;
            }

            // 归一化信号
            double[] normalizedSignal = new double[signal.length];
            for (int i = 0; i < signal.length; i++) {
                normalizedSignal[i] = signal[i] / rms;
            }
            normalizedSignals.add(normalizedSignal);
        }

        return normalizedSignals;
    }

    /**
     * 最多重复BPM结果类
     * 存储最多重复BPM计算结果的容器类
     */
    public static class RepeatedBPMResult {
        public final double mostRepeatedBPM; // 最多重复的BPM值
        public final int repeatCount; // 重复次数
        public final List<Double> sourceBPMs; // 所有参与统计的BPM值
        public final double secondMostRepeatedBPM; // 第二多重复的BPM值
        public final int secondRepeatCount; // 第二多重复的次数

        public RepeatedBPMResult(double mostRepeatedBPM, int repeatCount) {
            this.mostRepeatedBPM = mostRepeatedBPM;
            this.repeatCount = repeatCount;
            this.sourceBPMs = new ArrayList<>();
            this.secondMostRepeatedBPM = 0;
            this.secondRepeatCount = 0;
        }
        
        public RepeatedBPMResult(double mostRepeatedBPM, int repeatCount, 
                                double secondMostRepeatedBPM, int secondRepeatCount) {
            this.mostRepeatedBPM = mostRepeatedBPM;
            this.repeatCount = repeatCount;
            this.sourceBPMs = new ArrayList<>();
            this.secondMostRepeatedBPM = secondMostRepeatedBPM;
            this.secondRepeatCount = secondRepeatCount;
        }
    }
    
    /**
     * 频带BPM信息类
     * 存储每个频带的BPM和循环次数信息
     */
    private static class BandBPMInfo {
        final int bandIndex;
        final double bpm;
        final int count;
        
        BandBPMInfo(int bandIndex, double bpm, int count) {
            this.bandIndex = bandIndex;
            this.bpm = bpm;
            this.count = count;
        }
    }

    /**
     * 获取筛选后的BPM候选值
     * 简化实现：根据第一频繁和第二频繁的BPM值及其出现次数差异决定输出
     * 
     * @return 筛选后的BPM候选值列表
     */
    public List<Double> getAllBpmCandidates() {
        List<Double> candidates = new ArrayList<>();
        
        // 如果repeatedBPMResult不为空，返回筛选后的候选BPM值
        if (repeatedBPMResult != null) {
            // 添加第一频繁的BPM值（限制在60-180范围内）
            if (repeatedBPMResult.mostRepeatedBPM >= 60 && repeatedBPMResult.mostRepeatedBPM <= 180) {
                candidates.add(repeatedBPMResult.mostRepeatedBPM);
            }
            
            // 检查第二频繁的BPM值是否存在且与第一频繁的差异较大
            if (repeatedBPMResult.secondMostRepeatedBPM > 0 && repeatedBPMResult.mostRepeatedBPM > 0) {
                // 计算两个BPM值的比值（确保比值<=1）
                double ratio = Math.min(repeatedBPMResult.secondMostRepeatedBPM, repeatedBPMResult.mostRepeatedBPM) / 
                              Math.max(repeatedBPMResult.secondMostRepeatedBPM, repeatedBPMResult.mostRepeatedBPM);
                // 如果比值小于0.995且大于0.8（即第二频繁BPM值与第一频繁BPM值差异适中），则也添加第二频繁的BPM值（限制在60-180范围内）
                if (ratio < 0.995 && ratio > 0.8 && repeatedBPMResult.secondMostRepeatedBPM >= 60 && repeatedBPMResult.secondMostRepeatedBPM <= 180) {
                    candidates.add(repeatedBPMResult.secondMostRepeatedBPM);
                }
            }
            
            // 为每个有效的BPM值生成倍频候选值（1/2倍和2倍），并确保它们在60-180范围内
            List<Double> additionalCandidates = new ArrayList<>();
            for (Double bpm : candidates) {
                // 添加1/2倍频（如果在范围内）
                double halfBpm = bpm / 2.0;
                if (halfBpm >= 60 && halfBpm <= 180) {
                    additionalCandidates.add(halfBpm);
                }
                
                // 添加2倍频（如果在范围内）
                double doubleBpm = bpm * 2.0;
                if (doubleBpm >= 60 && doubleBpm <= 180) {
                    additionalCandidates.add(doubleBpm);
                }
            }
            
            // 将倍频候选值添加到主候选列表中（避免重复）
            for (Double additional : additionalCandidates) {
                if (!candidates.contains(additional)) {
                    candidates.add(additional);
                }
            }
            
            return candidates;
        }
        
        // 如果repeatedBPMResult为空，返回包含主要BPM的列表
        if (bpm > 0) {
            // 只添加在正常范围内的BPM值
            if (bpm >= 60 && bpm <= 180) {
                candidates.add(bpm);
                // 添加半速BPM作为候选（如果在范围内）
                double halfBpm = bpm / 2.0;
                if (halfBpm >= 60 && halfBpm <= 180) {
                    candidates.add(halfBpm);
                }
                
                // 添加2倍速BPM作为候选（如果在范围内）
                double doubleBpm = bpm * 2.0;
                if (doubleBpm >= 60 && doubleBpm <= 180) {
                    candidates.add(doubleBpm);
                }
            }
        }
        
        return candidates;
    }

    public AudioData getAudioData() {
        return audioData;
    }

    public int getAudioDurationMs() {
        return audioDurationMs;
    }
    
    /**
     * 获取目标采样率
     * 
     * @return 目标采样率
     */
    public int getTargetRate() {
        return targetRate;
    }
    
    /**
     * 获取hop大小
     * 
     * @return hop大小
     */
    public int getHopSize() {
        return hopSize;
    }
    
    /**
     * 获取频带定义
     * 
     * @return 频带定义数组
     */
    public double[] getFrequencyBands() {
        return FREQUENCY_BANDS;
    }
    
    /**
     * 获取最佳频带索引列表
     * 
     * @return 最佳频带索引列表
     */
    public List<Integer> getCoreBandIndices() {
        return coreBandIndices;
    }
    
    /**
     * 获取最佳频带索引
     * 
     * @return 最佳频带索引
     */
    public int getCoreBandIndex() {
        return coreBandIndex;
    }
    
    /**
     * 获取检测到的BPM值
     * 
     * @return BPM值
     */
    public double getBpm() {
        return bpm;
    }
    
    /**
     * 获取频带能量信号
     * 
     * @return 频带能量信号列表
     */
    public List<double[]> getBandEnergySignals() {
        return bandEnergySignals;
    }
}